#define FUSE_USE_VERSION 26
#include <iostream>
#include <string>
#include <Socket.h>
#include <AddrLinkedList.h>
#include <Instruction.h>
#include <Messager.h>
#include <mutex>
#include <fstream>
#include <fuse.h>
#include <FuseOperation.h>
using namespace std;
//用户环境列表
AddrLinkedList users;
//互斥锁，避免线程之间操作混乱无序
mutex mu;

void serve(Socket socket)
{
	
	Messager::log("Normal", "收到连接");
	Messager messager(socket);
	Instruction instruction;
	users.push((void*)(&instruction));
	while(true)
	{
		//接收指令
		string msg;
		try
		{
			msg = messager.recv();
			Messager::log("Normal", msg);
		}catch(string s)
		{
			
			Messager::log("Error", "接收异常,可能是客户端已经关闭退出");
			users.remove((void*)&instruction);
			break;
		}
		
		//处理
		//加锁
		mu.lock();
		string result;
		try
		{
			result = instruction.execute(msg);
		}catch(string s)
		{
			result = s;
		}catch(FCBInvalidError e)   //如果当前路径不存在（可能另一个客户端删了）
		{
			result = "访问异常,访问到了错误的位置\n";
			Messager::log("Error", result);
			instruction.execute("cd /");
		}
		
		//解锁
		mu.unlock();
		//返回当前目录
		if(!messager.send(instruction.getCurrentDirName()))
		{
			Messager::log("Error", "结果返回失败");
			continue;
		}
		
		//返回结果
		messager.send(result);
		
	}
	socket.Close();
}

int clientMode(){

	Socket socket;
	
	//如果监听失败
	if(!socket.Listen(8888, 20))
	{
		Messager::log("Error", "创建服务出错");
		exit(0);	
	}
	
	Messager::log("Normal", "文件服务被创建，正在8888端口监听...");
	
	//循环接收请求
	while(true)
	{
		Socket client = socket.Accept();
		thread manager(serve, client);
		manager.detach();
	}
}

int fuseMode(string filename, int filesize, int argc, char* argv[]){
	// cout << "fuse mode" << endl;
	// cout << filename << endl;
	// cout << filesize << endl;
	// cout << argc << endl;
	// for(int i = 0; i < argc; i++){
	// 	cout << i << ":" << argv[i] << endl;
	// }
	//判断文件是否存在
	ifstream file;
	file.open(filename + ".disk", ios::binary | ios::in);
	Instruction instruct;
	if(file.fail()) // 不存在
	{
		cout << "正在创建虚拟磁盘:" << filename << endl;
		vector<string> args;
		args.push_back("create");
		args.push_back(filename);
		args.push_back(to_string(filesize));
		cout << instruct.create(args) << endl;
		cout << "创建完毕"<< endl;
	}else{
		cout << "复用已有虚拟磁盘:" << filename << endl;
	}
	file.close();

	(argv-1)[0] = "lightfs";
	fuse_oper.getattr	= lightfs_getattr;  // 因为使用fuse_oper = {.getattr = xxx} 这种方式需要保证顺序，所以不用
	fuse_oper.open		= lightfs_open;
	fuse_oper.read		= lightfs_read;
	fuse_oper.readdir	= lightfs_readdir;
	return fuse_main(argc + 1, argv - 1, &fuse_oper, NULL);
}

void help(){
	cout << "使用方法：./server <模式> [options...]" << endl; 
	cout << "模式说明：" << endl; 
	cout << "fuse   使用fuse使用的模式" << endl;
	cout << "client 使用额外客户端连接使用的模式" << endl;
	cout << "help   查看帮助" << endl;
	cout << "fuse模式参数说明： ./server fuse <file> <size> [fuseOptions...]" << endl; 
	cout << "<file> 要使用作为虚拟文件系统的文件,不存在则创建" << endl;
	cout << "<size> 文件大小，单位M,如果文件已存在则忽略此参数" << endl;
	cout << "client模式说明：./server client" << endl; 
	cout << "无" << endl;
}

void badArgument(string reason){
	Messager::log("Error", "参数错误: " + reason);
	help();
	exit(-1);
}

int main(int argc, char* argv[])
{
	if(argc == 1){
		badArgument("至少有一个参数");
	}
	string mode(argv[1]);
	if(mode == "help"){
		help();
		return 0;
	}else if(mode == "fuse"){
		if(argc < 4){
			badArgument("fuse模式至少有2个参数");
		}
		string filename(argv[2]);
		string filesize(argv[3]);
		return fuseMode(filename, atoi(filesize.c_str()), argc - 4, argv + 4);
	}else if(mode == "client"){
		return clientMode();
	}else{
		badArgument("无法识别的模式 " + mode);
	}

	return 0;	
}